import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like } from 'typeorm';
import { Article } from './entities/article.entity';
import { CreateArticleDto } from './dto/create-article.dto';
import { UpdateArticleDto } from './dto/update-article.dto';
import { QueryArticlesDto } from './dto/query-articles.dto';
import * as marked from 'marked';

@Injectable()
export class ArticlesService {
  constructor(
    @InjectRepository(Article)
    private articlesRepository: Repository<Article>,
  ) {
    // 配置 marked
    marked.setOptions({
      breaks: true,
      gfm: true,
    });
  }

  async create(authorId: number, createArticleDto: CreateArticleDto): Promise<Article> {
    // 将 Markdown 转换为 HTML
    const contentHtml = await marked.parse(createArticleDto.content);

    const article = this.articlesRepository.create({
      ...createArticleDto,
      authorId,
      contentHtml,
      publishedAt: createArticleDto.status === 'published' ? new Date() : null,
    });

    return await this.articlesRepository.save(article);
  }

  async findAll(query: QueryArticlesDto, userId?: number) {
    const {
      page = 1,
      limit = 20,
      category,
      tag,
      status = 'published',
      search,
      sortBy = 'latest',
      authorId,
    } = query;

    const queryBuilder = this.articlesRepository
      .createQueryBuilder('article')
      .leftJoinAndSelect('article.author', 'author');

    // 筛选条件
    if (category) {
      queryBuilder.andWhere('article.category = :category', { category });
    }

    if (tag) {
      queryBuilder.andWhere('article.tags LIKE :tag', { tag: `%${tag}%` });
    }

    if (status) {
      queryBuilder.andWhere('article.status = :status', { status });
    }

    if (authorId) {
      queryBuilder.andWhere('article.authorId = :authorId', { authorId });
    }

    // 搜索
    if (search) {
      queryBuilder.andWhere(
        '(article.title LIKE :search OR article.excerpt LIKE :search OR article.content LIKE :search)',
        { search: `%${search}%` },
      );
    }

    // 排序
    switch (sortBy) {
      case 'latest':
        queryBuilder.orderBy('article.publishedAt', 'DESC');
        break;
      case 'oldest':
        queryBuilder.orderBy('article.publishedAt', 'ASC');
        break;
      case 'popular':
        queryBuilder.orderBy('article.views', 'DESC');
        break;
      case 'trending':
        queryBuilder.orderBy('article.likes', 'DESC');
        break;
      default:
        queryBuilder.orderBy('article.createdAt', 'DESC');
    }

    // 分页
    const skip = (page - 1) * limit;
    queryBuilder.skip(skip).take(limit);

    const [data, total] = await queryBuilder.getManyAndCount();

    return {
      data,
      total,
      page: Number(page),
      limit: Number(limit),
      totalPages: Math.ceil(total / limit),
    };
  }

  async findOne(id: number): Promise<Article> {
    const article = await this.articlesRepository.findOne({
      where: { id },
      relations: ['author'],
    });

    if (!article) {
      throw new NotFoundException(`文章 #${id} 不存在`);
    }

    // 如果 contentHtml 为空，临时渲染 Markdown
    if (!article.contentHtml && article.content) {
      article.contentHtml = await marked.parse(article.content);
    }

    // 增加浏览量
    await this.incrementViews(id);

    return article;
  }

  async findBySlug(slug: string): Promise<Article> {
    const article = await this.articlesRepository.findOne({
      where: { slug },
      relations: ['author'],
    });

    if (!article) {
      throw new NotFoundException(`文章 ${slug} 不存在`);
    }

    // 如果 contentHtml 为空，临时渲染 Markdown
    if (!article.contentHtml && article.content) {
      article.contentHtml = await marked.parse(article.content);
    }

    // 增加浏览量
    await this.incrementViews(article.id);

    return article;
  }

  async update(id: number, updateArticleDto: UpdateArticleDto): Promise<Article> {
    const article = await this.findOne(id);

    // 如果内容更新了，重新转换 Markdown
    if (updateArticleDto.content && updateArticleDto.content !== article.content) {
      updateArticleDto['contentHtml'] = await marked.parse(updateArticleDto.content);
    }

    // 如果状态改为已发布，设置发布时间
    if (updateArticleDto.status === 'published' && !article.publishedAt) {
      updateArticleDto['publishedAt'] = new Date();
    }

    Object.assign(article, updateArticleDto);
    return await this.articlesRepository.save(article);
  }

  async remove(id: number): Promise<void> {
    const article = await this.findOne(id);
    await this.articlesRepository.remove(article);
  }

  async incrementViews(id: number): Promise<void> {
    await this.articlesRepository.increment({ id }, 'views', 1);
  }

  async incrementLikes(id: number): Promise<void> {
    await this.articlesRepository.increment({ id }, 'likes', 1);
  }

  async getFeatured(limit = 5): Promise<Article[]> {
    return await this.articlesRepository.find({
      where: { isFeatured: true, status: 'published' },
      order: { publishedAt: 'DESC' },
      take: limit,
      relations: ['author'],
    });
  }

  async getRelated(articleId: number, limit = 5): Promise<Article[]> {
    const article = await this.findOne(articleId);
    
    // 基于分类和标签查找相关文章
    const queryBuilder = this.articlesRepository
      .createQueryBuilder('article')
      .leftJoinAndSelect('article.author', 'author')
      .where('article.id != :id', { id: articleId })
      .andWhere('article.status = :status', { status: 'published' });

    if (article.category) {
      queryBuilder.andWhere('article.category = :category', { category: article.category });
    }

    queryBuilder
      .orderBy('article.publishedAt', 'DESC')
      .take(limit);

    return await queryBuilder.getMany();
  }

  async getCategories(): Promise<{ category: string; count: number }[]> {
    const result = await this.articlesRepository
      .createQueryBuilder('article')
      .select('article.category', 'category')
      .addSelect('COUNT(*)', 'count')
      .where('article.status = :status', { status: 'published' })
      .andWhere('article.category IS NOT NULL')
      .groupBy('article.category')
      .orderBy('count', 'DESC')
      .getRawMany();

    return result;
  }

  async getTags(): Promise<{ tag: string; count: number }[]> {
    const articles = await this.articlesRepository.find({
      where: { status: 'published' },
      select: ['tags'],
    });

    const tagCounts = new Map<string, number>();
    
    articles.forEach(article => {
      if (article.tags && article.tags.length > 0) {
        article.tags.forEach(tag => {
          tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
        });
      }
    });

    return Array.from(tagCounts.entries())
      .map(([tag, count]) => ({ tag, count }))
      .sort((a, b) => b.count - a.count);
  }
}

